package de.lns.render;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;

import java.nio.FloatBuffer;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

import de.lns.level.Level;
import de.lns.tick.UpdateThread;
import de.lns.tick.State;


public final class Renderer {
	/**Make the constructor invisible.
	 * Since this is a static-access class,
	 * it shouldn't be instantiated.
	 */
	private Renderer(){};
	
	//Main part of the class starts here//
	private static int vboVert;
	private static int vboTex;
	private static FloatBuffer buf;
	private static FloatBuffer map;
	private static float mapRatio;
	
	
	protected static ShaderProgram shader;
	
	public static void tick() {
		mapRatio = getScreenHeight()/Level.getMap().getMesh().get(3);
		
		//| GL_DEPTH_BUFFER_BIT
		glClear(GL_COLOR_BUFFER_BIT);
		glUseProgram(shader.programPointer);
		
		State.active().queue().render();
		
		glUseProgram(0);
		
		
	}
	
	public static void initialize() {
		initializeDisplay();
		
		//Print OpenGL version.
		//System.out.println(glGetString(GL_VERSION));
		try {
			DisplayMode[] modes = Display.getAvailableDisplayModes();
//			for(DisplayMode d: modes){
//				System.out.println(d);
//			}
		} catch (LWJGLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		initializeOpenGL();
		
		buf = ModelFactory.genRectMesh(1, 1);
		map = ModelFactory.genRectMap();
		
		vboVert = glGenBuffers();
		glBindBuffer(GL_ARRAY_BUFFER, vboVert);
		glBufferData(GL_ARRAY_BUFFER, buf, GL_STREAM_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		

		vboTex = glGenBuffers();
		glBindBuffer(GL_ARRAY_BUFFER, vboTex);
		glBufferData(GL_ARRAY_BUFFER, map, GL_STREAM_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		
		shader = ShaderProgram.createProgram("simple");

		mapRatio = getScreenHeight()/Level.getMap().getMesh().get(3);
	}

	public static void dispose() {
		glUseProgram(0);
		//Free all Graphics Card memory occupied by shader programs
		if(shader!=null){
			shader.dispose();
		}
		
		//Dispose all loaded images.
		TextureLoader.dispose();
		
		//Free all resources, occupied by Display.
		Display.destroy();
	}
	
	private static void initializeDisplay() {
		try {
			Display.setTitle("Lasers 'n' Stuff");
			//Set the Resolution to the same as the Desktop's.
			//Display.setDisplayMode(new DisplayMode(800, 600));
			Display.setDisplayMode(Display.getDesktopDisplayMode());
			//Set the Display to fullscreen.
			Display.setFullscreen(true);
			//Show the Display.
			Display.create();
			Display.makeCurrent();
			//System.out.println(Integer.toString(Display.getWidth()) + " | " +  Integer.toString(Display.getHeight()));
		} catch (LWJGLException e) {
			UpdateThread.kill("Error while setting up Display" + 
					"\nGraphics-Adapter: " + Display.getAdapter(), e);
		}
	}
	
	private static void initializeOpenGL() {
		//glOrtho(0, 500, 0, 500, 10, -1);
		glLoadIdentity();
		glMatrixMode(GL_MODELVIEW);
		glOrtho(0, Display.getDisplayMode().getWidth(), 0, Display.getDisplayMode().getHeight(), 10f, -1f);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	}
	
	protected static int vertexPointer() {
		return vboVert;
	}
	
	protected static int mappingPointer() {
		return vboTex;
	}
	
	public static float getMapRatio() {
		return mapRatio;
	}
	
	public static int getScreenWidth() {
		return Display.getDisplayMode().getWidth();
	}
	
	public static int getScreenHeight() {
		return Display.getDisplayMode().getHeight();
	}
	
}
